package com.asm.service;

import com.asm.dto.PageResult;
import com.asm.entity.sys.Community;
import com.asm.entity.sys.District;
import com.asm.entity.sys.Spot;
import com.asm.repository.CommunityRepository;
import com.asm.repository.DistrictRepository;
import com.asm.repository.SpotRepository;
import com.asm.util.SnowflakeIdWorker;
import com.asm.vo.sys.HomeVo;
import com.asm.vo.sys.SpotReserveVo;
import com.asm.vo.sys.SpotVo;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @author ZhuangGuiMan
 */
@Service
@Slf4j
public class SpotService {
    @Resource
    private SpotRepository spotRepository;

    @Resource
    private CommunityRepository communityRepository;

    @Resource
    private DistrictRepository districtRepository;

    @Resource
    private SnowflakeIdWorker snowflakeIdWorker;

    public HomeVo getHomeInfo() {
        val homeVo = new HomeVo();
        int totalNumber = spotRepository.countTotalNumber();
        int freeNumber = spotRepository.countFreeNumber();
        int inUseNumber = spotRepository.countInUse();
        int expireNumber = spotRepository.countExpire();
        int repairNumber = spotRepository.countRepair();
        log.info("totalNumber is : " + totalNumber);
        log.info("freeNumber is : " + freeNumber);
        log.info("inUseNumber is : " + inUseNumber);
        log.info("expireNumber is : " + expireNumber);
        log.info("repairNumber is : " + repairNumber);
        homeVo.setSpotTotalNumber(totalNumber);
        homeVo.setSpotFreeNumber(freeNumber);
        homeVo.setSpotInUse(inUseNumber);
        homeVo.setSpotExprire(expireNumber);
        homeVo.setSpotRepair(repairNumber);
        return homeVo;
    }

    /**
     * 获取广告位列表
     *
     * @param page 页面对象
     * @return 广告位列表
     */
    private List<SpotVo> getSpotVoList(Page<Spot> page) {
        List<SpotVo> list = new ArrayList<>();
        for (Spot spot : page.getContent()) {
            SpotVo spotVo = new SpotVo();
            BeanUtils.copyProperties(spot, spotVo);
            list.add(spotVo);
        }
        return list;
    }

    /**
     * 分页查询所有广告位
     *
     * @param pageNumber 当前页码
     * @param pageSize   页面大小
     * @return 分页形式的广告位列表
     */
    public PageResult<SpotVo> findAllSpots(Integer pageNumber, Integer pageSize) {
        Page<Spot> page = spotRepository.findAll(PageRequest.of(pageNumber, pageSize));
        List<SpotVo> list = getSpotVoList(page);
        for (SpotVo spotVo : list) {

            /* 根据档期最晚时间刷新广告位状态*/
            Date date = spotRepository.getLatestReserveDateBySpotId(spotVo.getId());
            if (date == null || date.before(new Date())) {
                spotVo.setIsBusy(false);
                Spot spot = spotRepository.findSpotById(spotVo.getId());
                spot.setIsBusy(false);
                spotRepository.save(spot);
            } else {
                spotVo.setIsBusy(true);
                Spot spot = spotRepository.findSpotById(spotVo.getId());
                spot.setIsBusy(true);
                spotRepository.save(spot);
            }

            /* 设置小区名*/
            Community community = communityRepository.findCommunityById(spotVo.getCommunityId());
            if (community == null) {
                continue;
            }
            spotVo.setCommunityName(community.getName());
        }
        return new PageResult<>(pageNumber, pageSize, page.getTotalPages(), list);
    }

    /**
     * 根据id查询广告位
     *
     * @param id 广告位编号
     * @return 广告位
     */
    public SpotVo findSpotById(Long id) {
        Spot spot = spotRepository.findSpotById(id);
        SpotVo spotVo = new SpotVo();
        BeanUtils.copyProperties(spot, spotVo);
        return spotVo;
    }

    /**
     * 根据广告位编号查询广告位预定信息
     *
     * @param id 广告位编号
     * @return 广告位信息
     */
    public SpotReserveVo getSpotReserveBySpotId(Long id) {
        SpotReserveVo spotReserveVo = new SpotReserveVo();
        Spot spot = spotRepository.findSpotById(id);
        spotReserveVo.setSpotId(id);
        spotReserveVo.setSpotType(spot.getSpotType());
        spotReserveVo.setSpotSize(spot.getSpotSize());
        Community community = communityRepository.findCommunityById(spot.getCommunityId());
        spotReserveVo.setCommunity(community.getName());
        District district = districtRepository.findDistinctById(community.getDistrictId());
        spotReserveVo.setProvince(district.getProvince());
        spotReserveVo.setCity(district.getCity());
        spotReserveVo.setDistrict(district.getDistrict());
        return spotReserveVo;
    }

    /**
     * 根据广告位类型分页查询广告位
     *
     * @param type       广告位类型
     * @param pageNumber 当前页码
     * @param pageSize   页面大小
     * @return 分页形式的广告位列表
     */
    public PageResult<SpotVo> findSpotByType(String type, Integer pageNumber, Integer pageSize) {
        Pageable page = PageRequest.of(pageNumber, pageSize);
        Page<Spot> spots = spotRepository.findBySpotTypeAndIsDel(type, false, page);
        return new PageResult<>(pageNumber, pageSize, spots.getTotalPages(), getSpotVoList(spots));
    }

    /**
     * 根据广告位大小分页查询广告位
     *
     * @param size       广告位大小
     * @param pageNumber 当前页码
     * @param pageSize   页面大小
     * @return 分页形式的广告位列表
     */
    public PageResult<SpotVo> findSpotBySize(String size, Integer pageNumber, Integer pageSize) {
        Pageable page = PageRequest.of(pageNumber, pageSize);
        Page<Spot> spots = spotRepository.findBySpotSizeAndIsDel(size, false, page);
        return new PageResult<>(pageNumber, pageSize, spots.getTotalPages(), getSpotVoList(spots));
    }

    /**
     * 根据小区编号分页查询广告位
     *
     * @param communityId 广告位大小
     * @param pageNumber  当前页码
     * @param pageSize    页面大小
     * @return 分页形式的广告位列表
     */
    public PageResult<SpotVo> findSpotByCommunityId(Long communityId, Integer pageNumber, Integer pageSize) {
        Pageable page = PageRequest.of(pageNumber, pageSize);
        Page<Spot> spots = spotRepository.findByCommunityIdAndIsDel(communityId, false, page);
        return new PageResult<>(pageNumber, pageSize, spots.getTotalPages(), getSpotVoList(spots));
    }

    /**
     * 添加广告位
     *
     * @param spotVo 广告位
     * @return 广告位编号
     */
    @Transactional(rollbackFor = Exception.class)
    public Long addSpot(SpotVo spotVo) {
        Spot spot = new Spot();
        BeanUtils.copyProperties(spotVo, spot);
        spot.setId(snowflakeIdWorker.nextId());
        spot.setCreateAt(new Date());
        spot.setCreateBy(1L);
        spot.setUpdateAt(new Date());
        spot.setUpdateBy(1L);
        spotRepository.save(spot);
        return spot.getId();
    }

    /**
     * 更新广告位
     *
     * @param spotVo 广告位
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateSpot(SpotVo spotVo) {
        Optional<Spot> optionalSpot = spotRepository.findById(spotVo.getId());
        if (optionalSpot.isPresent()) {
            Spot spot = optionalSpot.get();
            BeanUtils.copyProperties(spotVo, spot);
            spot.setUpdateBy(1L);
            spot.setUpdateAt(new Date());
            spotRepository.save(spot);
        }
    }

    /**
     * 根据Id删除广告位
     *
     * @param id 广告位编号
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteSpot(Long id) {
        Optional<Spot> optionalSpot = spotRepository.findById(id);
        if (optionalSpot.isPresent()) {
            Spot spot = optionalSpot.get();
            spot.setIsDel(true);
            spot.setUpdateBy(1L);
            spot.setUpdateAt(new Date());
            spotRepository.save(spot);
        }
    }

    /**
     * 判断是否重复预订相同档期的广告位
     *
     * @param userId    用户Id
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 是否已被预订
     */
    public Boolean isSpotReserved(Long userId, Long spotId, Date startDate, Date endDate) {
        Long id = spotRepository.findByUserIdAndSchedule(userId, spotId, startDate, endDate);
        return id != null;
    }

    /**
     * 根据广告位Id查询最晚档期结束时间
     *
     * @param spotId 广告位Id
     * @return 最晚档期结束时间
     */
    public Date getLatestReserveDateBySpotId(Long spotId) {
        return spotRepository.getLatestReserveDateBySpotId(spotId);
    }

}
